import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.io.Serializable;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.TextMessage;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

public class WhiteBoardServer {

	private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;

	WhiteBoardModel model;

	// HashMap<String, WhiteBoardClient> clientsName = new HashMap<String,
	// WhiteBoardClient>();

	HashMap<String, Color> clientsColor = new HashMap<String, Color>();

	int colorCounter = 0;

	WhiteBoard board;

	ServerApplication slave;

	Subscriber loginSubscriber;
	Subscriber logoutSubscriber;
	Subscriber lineSubscriber;
	Publisher recvPublisher;
	Publisher clearPublisher;

	TopicConnection connection;

	public WhiteBoardServer() {

		model = new WhiteBoardModel();
		board = new WhiteBoard(model, "White Board Server");

		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				try {
					connection.close();
				} catch (JMSException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}
		});

		try {
			TopicConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
			connection = connectionFactory.createTopicConnection();

			loginSubscriber = new Subscriber("Login", connection, null);
			loginSubscriber.getSub().setMessageListener(new MessageListener() {

				@Override
				public void onMessage(Message m) {
					System.out.println("THERE!!");
					ObjectMessage msg = (ObjectMessage) m;
					try {
						ArrayList<Serializable> lst = (ArrayList<Serializable>) msg.getObject();
						login((String) lst.get(0), (Color) lst.get(1));

					} catch (JMSException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

				}

			});

			connection.setExceptionListener(new ExceptionListener() {

				@Override
				public void onException(JMSException arg0) {
					arg0.printStackTrace();
					// System.err.println();

				}

			});
			logoutSubscriber = new Subscriber("Logout", connection, null);
			logoutSubscriber.getSub().setMessageListener(new MessageListener() {

				@Override
				public void onMessage(Message m) {
					ObjectMessage msg = (ObjectMessage) m;
					try {
						ArrayList<Serializable> lst = (ArrayList<Serializable>) msg.getObject();
						logout((String) lst.get(0));

					} catch (JMSException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

				}

			});
			lineSubscriber = new Subscriber("Line", connection, null);
			lineSubscriber.getSub().setMessageListener(new MessageListener() {

				@Override
				public void onMessage(Message m) {
					ObjectMessage msg = (ObjectMessage) m;
					try {
						ArrayList<Serializable> lst = (ArrayList<Serializable>) msg.getObject();
						line((String) lst.get(0), (Point) lst.get(1), (Point) lst.get(2));

					} catch (JMSException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

				}

			});
			recvPublisher = new Publisher("Recv", connection);
			clearPublisher = new Publisher("Clear", connection);
			connection.start(); 
		} catch (JMSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public WhiteBoard getBoard() {
		return board;
	}

	public void login(String name, Color color) {
		slave.appendMessage("Client " + name + " connecting.");
		// clientsName.put(name, client);
		if (color == null || clientsColor.containsValue(color)) {
			clientsColor.put(
					name,
					new Color( (int) (Math.random() * 256), (int) (Math.random() * 256), (int) (Math.random() * 256)));
			slave.appendMessage("A new color has been assigned to " + name);
		} else {
			slave.appendMessage("Proposed color accepted from " + name);
			clientsColor.put(name, color);
		}

	}

	public void logout(String name) {
		slave.appendMessage("Client " + name + " disconnecting...");
		if (clientsColor.containsKey(name)) {
			// clientsName.remove(name);
			clientsColor.remove(name);
			model.removeLines(clientsColor.get(name));

		} else {
			slave.appendMessage("Error! client " + name + " not registred!");
		}

	}

	public void line(String name, Point start, Point end) {
		if (clientsColor.containsKey(name)) {
			model.addLine(start, end, clientsColor.get(name));
			board.repaint();
			try {
				ArrayList<Serializable> lst = new ArrayList<Serializable>();

				lst.add(start);
				lst.add(end);
				lst.add(clientsColor.get(name));
				ObjectMessage m = recvPublisher.getSession().createObjectMessage(lst);
				m.setStringProperty("name", name);
				recvPublisher.getPub().send(m);

			} catch (JMSException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			// clientsName.get(name).receiveLine(start, end,
			// clientsColor.get(name));
			// clientsName.get(name).receiveLine(start, end,
			// clientsColor.get(name));

		}

		// clientsName.get(name).receiveLine(start, end,
		// clientsColor.get(name));
		// TODO
	}

	public void setSlave(ServerApplication sa) {
		slave = sa;

	}

	public void clear() {
		model.clear();
		board.repaint();
		TextMessage msg;
		try {
			msg = clearPublisher.getSession().createTextMessage();
			clearPublisher.getPub().send(msg);
		} catch (JMSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}
